/**
 *  (c)
 * <p>
 *
 * <p>
 *
 */

package com.nn.smart.bus.controller;

import com.nn.smart.bus.commons.tools.annotation.LogOperation;
import com.nn.smart.bus.commons.tools.constant.Constant;
import com.nn.smart.bus.commons.tools.exception.ErrorCode;
import com.nn.smart.bus.commons.tools.page.PageData;
import com.nn.smart.bus.commons.tools.security.bo.ResourceBO;
import com.nn.smart.bus.commons.tools.security.password.PasswordUtils;
import com.nn.smart.bus.commons.tools.security.user.SecurityUser;
import com.nn.smart.bus.commons.tools.security.user.UserDetail;
import com.nn.smart.bus.commons.tools.utils.ConvertUtils;
import com.nn.smart.bus.commons.tools.utils.ExcelUtils;
import com.nn.smart.bus.commons.tools.utils.Result;
import com.nn.smart.bus.commons.tools.validator.AssertUtils;
import com.nn.smart.bus.commons.tools.validator.ValidatorUtils;
import com.nn.smart.bus.commons.tools.validator.group.AddGroup;
import com.nn.smart.bus.commons.tools.validator.group.DefaultGroup;
import com.nn.smart.bus.commons.tools.validator.group.UpdateGroup;
import com.nn.smart.bus.dto.*;
import com.nn.smart.bus.dto.epdc.GridLeaderRegisterDTO;
import com.nn.smart.bus.dto.epdc.form.EpdcScripUserInfoFormDTO;
import com.nn.smart.bus.excel.SysUserExcel;
import com.nn.smart.bus.service.*;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import springfox.documentation.annotations.ApiIgnore;

import javax.servlet.http.HttpServletResponse;
import java.util.List;
import java.util.Map;

/**
 * 用户管理
 */
@RestController
@RequestMapping("user")
@Api(tags = "用户管理")
public class SysUserController {
    @Autowired
    private SysUserService sysUserService;
    @Autowired
    private SysRoleUserService sysRoleUserService;
    @Autowired
    private SysRoleDataScopeService sysRoleDataScopeService;
    @Autowired
    private SysResourceService sysResourceService;
    @Autowired
    private SysDeptService sysDeptService;

    @GetMapping("page")
    @ApiOperation("分页")
    @ApiImplicitParams({
            @ApiImplicitParam(name = Constant.PAGE, value = "当前页码，从1开始", paramType = "query", required = true, dataType = "int"),
            @ApiImplicitParam(name = Constant.LIMIT, value = "每页显示记录数", paramType = "query", required = true, dataType = "int"),
            @ApiImplicitParam(name = Constant.ORDER_FIELD, value = "排序字段", paramType = "query", dataType = "String"),
            @ApiImplicitParam(name = Constant.ORDER, value = "排序方式，可选值(asc、desc)", paramType = "query", dataType = "String"),
            @ApiImplicitParam(name = "username", value = "用户名", paramType = "query", dataType = "String")
    })
    public Result<PageData<SysUserDTO>> page(@ApiIgnore @RequestParam Map<String, Object> params) {
        PageData<SysUserDTO> page = sysUserService.page(params);

        return new Result<PageData<SysUserDTO>>().ok(page);
    }

    @GetMapping("{id}")
    @ApiOperation("信息")
    public Result<SysUserDTO> get(@PathVariable("id") Long id) {
        SysUserDTO data = sysUserService.get(id);

        //用户角色列表
        List<Long> roleIdList = sysRoleUserService.getRoleIdList(id);
        data.setRoleIdList(roleIdList);

        return new Result<SysUserDTO>().ok(data);
    }

    /**
     * @param userId
     * @return com.nn.smart.bus.commons.tools.utils.Result<java.util.List < java.lang.Long>>
     * @author nanning
     * @Description 查询用户角色Id
     * @Date 2020/2/3 8:13
     **/
    @GetMapping("getRoleIdList/{userId}")
    public Result<List<Long>> getRoleIdList(@PathVariable("userId") Long userId) {
        //用户角色列表
        List<Long> roleIdList = sysRoleUserService.getRoleIdList(userId);
        return new Result<List<Long>>().ok(roleIdList);
    }

    @GetMapping("info")
    @ApiOperation("登录用户信息")
    public Result<SysUserDTO> info(@ApiIgnore UserDetail user) {
        SysUserDTO data = ConvertUtils.sourceToTarget(user, SysUserDTO.class);
        return new Result<SysUserDTO>().ok(data);
    }

    @PostMapping
    @ApiOperation("保存")
    @LogOperation("Save User")
    public Result save(@RequestBody SysUserDTO dto) {
        //效验数据
        ValidatorUtils.validateEntity(dto, AddGroup.class, DefaultGroup.class);

        sysUserService.save(dto);

        return new Result();
    }

    @PutMapping
    @ApiOperation("修改")
    @LogOperation("Update User")
    public Result update(@RequestBody SysUserDTO dto) {
        //效验数据
        ValidatorUtils.validateEntity(dto, UpdateGroup.class, DefaultGroup.class);

        sysUserService.update(dto);

        return new Result();
    }

    @PutMapping("password")
    @ApiOperation("修改密码")
    @LogOperation("Password User")
    public Result password(@RequestBody PasswordDTO dto) {
        //效验数据
        ValidatorUtils.validateEntity(dto);

        UserDetail user = SecurityUser.getUser();

        //原密码不正确
        if (!PasswordUtils.matches(dto.getPassword(), user.getPassword())) {
            return new Result().error(ErrorCode.PASSWORD_ERROR);
        }

        sysUserService.updatePassword(user.getId(), dto.getNewPassword());

        return new Result();
    }

    @DeleteMapping
    @ApiOperation("删除")
    @LogOperation("Delete User")
    public Result delete(@RequestBody Long[] ids) {
        //效验数据
        AssertUtils.isArrayEmpty(ids, "id");

        sysUserService.delete(ids);

        return new Result();
    }

    @GetMapping("export")
    @ApiOperation("导出")
    @LogOperation("Export User")
    @ApiImplicitParam(name = "username", value = "用户名", paramType = "query", dataType = "String")
    public void export(@ApiIgnore @RequestParam Map<String, Object> params, HttpServletResponse response) throws Exception {
        List<SysUserDTO> list = sysUserService.list(params);

        ExcelUtils.exportExcelToTarget(response, null, list, SysUserExcel.class);
    }

    /**
     * 根据用户名，获取用户信息
     */
    @GetMapping("getByUsername")
    public Result<UserDetail> getByUsername(String username) {
        SysUserDTO user = sysUserService.getByUsername(username);

        UserDetail userDetail = ConvertUtils.sourceToTarget(user, UserDetail.class);
        //初始化用户数据
        initUserData(userDetail);

        return new Result<UserDetail>().ok(userDetail);
    }

    /**
     * 根据用户ID，获取用户信息
     */
    @GetMapping("getById")
    public Result<UserDetail> getById(Long id) {
        SysUserDTO user = sysUserService.get(id);

        UserDetail userDetail = ConvertUtils.sourceToTarget(user, UserDetail.class);
        //初始化用户数据
        initUserData(userDetail);

        return new Result<UserDetail>().ok(userDetail);
    }

    /**
     * 根据openId获取用户信息
     *
     * @return com.nn.smart.bus.commons.tools.utils.Result<com.nn.smart.bus.dto.SysUserDTO>
     * @params [openId]
     * @author nanning
     * @since 2019/11/20 13:54
     */
    @GetMapping("getUserInfo/{openId}")
    public Result<SysUserDTO> getSysUserInfoByOpenId(@PathVariable("openId") String openId) {
        SysUserDTO data = sysUserService.getSysUserInfoByOpenId(openId);

        return new Result<SysUserDTO>().ok(data);
    }

    /**
     * 根据用户ID 获取用户角色权限信息
     *
     * @return com.nn.smart.bus.commons.tools.utils.Result<java.util.List < com.nn.smart.bus.dto.DataScopeDeptList>>
     * @params [id]
     */
    @GetMapping("getDataScope")
    public Result<List<DataScopeDeptList>> getDataScopeList(Long id) {
        List<DataScopeDeptList> data = sysRoleDataScopeService.getDataScopeDetailList(id);

        return new Result<List<DataScopeDeptList>>().ok(data);
    }

    /**
     * 根据用户名更新用户微信openId
     *
     * @return com.nn.smart.bus.commons.tools.utils.Result
     * @params [sysUserOpenIdFormDto]
     * @author nanning
     * @since 2019/11/20 9:52
     */
    @PostMapping("modifyOpenId")
    public Result modifyOpenIdByUsername(@RequestBody SysUserOpenIdFormDTO sysUserOpenIdFormDto) {
        //效验数据
        ValidatorUtils.validateEntity(sysUserOpenIdFormDto);
        return sysUserService.modifyOpenIdByUsername(sysUserOpenIdFormDto);
    }

    /**
     * 初始化用户数据
     */
    private void initUserData(UserDetail userDetail) {
        if (userDetail == null) {
            return;
        }

        //用户机构类型键值
        SysDeptDTO deptDto = sysDeptService.get(userDetail.getDeptId());
        if (null != deptDto) {
            userDetail.setTypeKey(deptDto.getTypeKey());
        }

        //用户部门数据权限
        List<Long> deptIdList = sysRoleDataScopeService.getDataScopeList(userDetail.getId());
        userDetail.setDeptIdList(deptIdList);

        //用户资源列表
        List<ResourceBO> resourceList = sysResourceService.getUserResourceList(userDetail.getId());
        userDetail.setResourceList(resourceList);
    }

    /**
     * 网格长注册时，根据手机号，查询网格长管理的所有网格
     *
     * @param mobile
     * @return java.util.List<com.nn.smart.bus.dto.epdc.GridLeaderRegisterDTO>
     */
    @GetMapping("/listGridForLeader/{mobile}")
    public Result<GridLeaderRegisterDTO> listGridWhileLeaderRegister(@PathVariable("mobile") String mobile) {
        return sysUserService.listGridWhileLeaderRegister(mobile);
    }

    /**
     * 获取部门下的所有用户ID
     *
     * @return com.nn.smart.bus.commons.tools.utils.Result<java.util.List < java.lang.Long>>
     * @params [deptId]
     * @author nanning
     * @since 2019/10/29 17:31
     */
    @GetMapping("ids/{deptId}")
    public Result<List<Long>> getUserIdsByDeptIds(@PathVariable("deptId") Long deptId) {
        List<Long> data = sysUserService.listOfUserIdsByDeptId(deptId);
        return new Result<List<Long>>().ok(data);
    }

    /**
     * 组装用户部门多层结构
     * <p>auth模块调用，用户登录时，获取用户机构权限，返回页面组装下拉菜单所需数据，保存在redis</p>
     * <p>组装三层，街道-社区-网格</p>
     *
     * @param userId
     * @return com.nn.smart.bus.commons.tools.utils.Result
     */
    @GetMapping("packageOption/{userId}")
    public Result packageUserDeptOption(@PathVariable("userId") Long userId) {
        sysDeptService.packageUserDeptOption(userId);
        return new Result();
    }

    /**
     * 获取用户部门多层结构，用户前端显示，请求需携带token
     * <p>调接口，从redis获取{@link SysUserController#packageUserDeptOption(Long)}接口生成的数据。</p>
     * <p>此接口展示三级机构层级（街道-社区-网格），不包括区级</p>
     *
     * @return com.nn.smart.bus.commons.tools.utils.Result<com.nn.smart.bus.dto.DeptOption>
     * @author nanning
     * @date 2019/11/27 14:31
     */
    @GetMapping("deptOptions/getByLoginUser")
    public Result<DeptOption> getUserDeptOption() {
        DeptOption deptOption = sysDeptService.getUserDeptOption();
        return new Result().ok(deptOption);
    }

    /**
     * 获取用户部门多层结构（完整层级结构，包括顶级部门），用户前端显示，请求需携带token
     * <p>新闻、通知发布，选择机构可多选，且展示完整层级结构，市区-街道-社区-网格</p>
     * <P>新闻、通知页面主动触发，不在用户登录是自动调用</P>
     *
     * @return com.nn.smart.bus.commons.tools.utils.Result<com.nn.smart.bus.dto.DeptOption>
     * @author nanning
     * @date 2020/1/28 10:40
     */
    @GetMapping("deptOptions/getAllByLoginUser")
    public Result<DeptOption> getAllDeptOptionByLoginUser() {
        DeptOption option = sysDeptService.getAllDeptOptionByLoginUser();
        return new Result().ok(option);
    }

    /**
     * pc端页面，获取用户街道-社区层级关系，前端显示，请求需携带token
     * <p>只组装 街道-社区 两级
     * <li>相关页面：用户数据分析-网格开通情况</li>
     * </p>
     *
     * @return com.nn.smart.bus.commons.tools.utils.Result<com.nn.smart.bus.dto.DeptOption>
     * @author nanning
     * @date 2020/2/10 14:45
     */
    @GetMapping("deptOptions/getMiddleByLoginUser")
    public Result<DeptOption> getMiddleByLoginUser() {
        DeptOption option = sysDeptService.getMiddleByLoginUser();
        return new Result().ok(option);
    }

    /**
     * pc端页面，获取用户 所有街道权限，前端显示，请求需携带token
     * <p>只组装 街道 一级
     * <li>相关页面：用户数据分析-排名分析-居民注册</li>
     * <li>相关页面：用户数据分析-排名分析-党员注册</li>
     * </p>
     *
     * @return com.nn.smart.bus.commons.tools.utils.Result<com.nn.smart.bus.dto.DeptOption>
     * @author nanning
     * @date 2020/2/11 11:22
     */
    @GetMapping("deptOptions/getStreetByLoginUser")
    public Result<DeptOption> getStreetByLoginUser() {
        DeptOption option = sysDeptService.getStreetByLoginUser();
        return new Result().ok(option);
    }

    /**
     * 退出登录
     *
     * @param userId @RequestBody SysUserDTO dto
     * @return
     */
    @GetMapping("updateUserOpenId/{userId}")
    public Result updateUserOpenId(@PathVariable("userId") Long userId) {

        sysUserService.updateUserOpenId(userId);

        return new Result();
    }

    /**
     * @Description: 根据部门id，查询部门下的所有用户手机号
     * @Param: [deptId]
     * @return: com.nn.smart.bus.commons.tools.utils.Result<java.util.List < java.lang.String>>
     * @author nanning
     * @Date: 2020-01-09
     */
    @GetMapping("getUserPhoneByListDeptId")
    public Result<List<String>> getUserPhoneByListDeptId(@RequestBody List<Long> deptId) {
        return sysUserService.getUserPhoneByListDeptId(deptId);
    }

    /**
     * @Description: 根据议题网格ID查询拥有这个网格数据权限且是网格长的角色，再根据角色查出所有用户手机号
     * @Param: [deptId]
     * @return: com.nn.smart.bus.commons.tools.utils.Result<java.util.List < java.lang.String>>
     * @author nanning
     * @Date: 2020-01-09
     */
    @GetMapping("getSysGridLeaderPhone/{deptId}")
    public Result<List<String>> getSysGridLeaderPhone(@PathVariable("deptId") Long deptId) {
        return sysUserService.getSysGridLeaderPhone(deptId);
    }

    /**
     * @Description  根据手机号和网格信息获取临时凭证
     * @author nanning
     * @Date  2020/6/22
     * @Param [epdcScripUserInfoFormDTO]
     * @return com.nn.smart.bus.commons.tools.utils.Result<java.lang.String>
     **/
    @PostMapping("getUserInfoByGridAndMobile")
    public Result<String> getUserInfoByGridAndMobile(@RequestBody EpdcScripUserInfoFormDTO epdcScripUserInfoFormDTO){
        ValidatorUtils.validateEntity(epdcScripUserInfoFormDTO);
        return new Result<String>().ok(sysUserService.getUserInfoByGridAndMobile(epdcScripUserInfoFormDTO));
    }

    /**
     * @Description  根据临时凭证获取用户信息
     * @author nanning
     * @Date  2020/6/22
     * @Param [username]
     * @return com.nn.smart.bus.commons.tools.utils.Result<com.nn.smart.bus.commons.tools.security.user.UserDetail>
     **/
    @GetMapping("getByScrip/{scrip}")
    public Result<UserDetail> getByScrip(@PathVariable("scrip") String scrip) {
        SysUserDTO user = sysUserService.getByScrip(scrip);
        UserDetail userDetail = ConvertUtils.sourceToTarget(user, UserDetail.class);
        //初始化用户数据
        initUserData(userDetail);
        return new Result<UserDetail>().ok(userDetail);
    }

    /**
     * @Description  根据ID获取临时凭证
     * @author nanning
     * @Date  2020/12/11
     * @Param [epdcScripUserInfoFormDTO]
     * @return com.nn.smart.bus.commons.tools.utils.Result<java.lang.String>
     **/
    @PostMapping("getScripBySysUserId/{id}")
    public Result<String> getScripBySysUserId(@PathVariable Long id){
        return new Result<String>().ok(sysUserService.getScripBySysUserId(id));
    }
    /**
     * 获取用户部门多层结构，用户前端显示，请求需携带token - 工作日志使用
     *
     * @return com.nn.smart.bus.commons.tools.utils.Result<com.nn.smart.bus.dto.DeptOption>
     * @author nanning
     * @date 2020/1/27 14:31
     */
    @PostMapping("deptOptions/getUserDeptOptionByUserId")
    public Result<DeptOption> getUserDeptOptionByUserId() {
        return sysDeptService.getUserDeptOptionByUserId(String.valueOf(SecurityUser.getUserId()));
    }
}
